/* 
 * $Id: RepetitionNode.java 1259 2007-01-09 14:23:47Z tcoupaye $
 *
 * Behavior Protocols extensions for static and runtime checking
 * developed for the Julia implementation of Fractal.
 *
 * Copyright 2004
 *    Distributed Systems Research Group
 *    Department of Software Engineering
 *    Faculty of Mathematics and Physics
 *    Charles University, Prague
 *
 * Copyright (C) 2006
 *    Formal Methods In Software Engineering Group
 *    Institute of Computer Science
 *    Academy of Sciences of the Czech Republic
 *
 * Copyright (C) 2006 France Telecom
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 *
 * Contact: ft@nenya.ms.mff.cuni.cz
 * Authors: Jan Kofron <kofron@nenya.ms.mff.cuni.cz>
 */

package org.objectweb.fractal.bpc.checker.node;

import java.util.ArrayList;
import java.util.TreeSet;

import org.objectweb.fractal.bpc.checker.DFSR.CheckingException;
import org.objectweb.fractal.bpc.checker.state.*;
import org.objectweb.fractal.bpc.checker.utils.AnotatedProtocol;


/**
 * Represents repetition operator
 */
public class RepetitionNode extends TreeNode {

    /** Creates a new instance of RepetitionNode */
    public RepetitionNode(TreeNode node) {
        //super(node.getActiveEvents());
        super("(" + node.protocol + ")*");
        this.nodes = new TreeNode[1];
        this.nodes[0] = node;

        //this.initial = node.getInitial(); // this cannot be since forward
        // cutting may change the tree structure!!!
        this.initial = null;
        //this.initial.getSignature(new Signature(), 0);

    }

    /**
     * @see org.objectweb.fractal.bpc.checker.node.TreeNode#getInitial()
     */
    public State getInitial() {
        if (initial == null)
            initial = nodes[0].getInitial();

        return initial;
    }
    
    /**
     * @see org.objectweb.fractal.bpc.checker.node.TreeNode#isAccepting(org.objectweb.fractal.bpc.checker.state.State)
     */
    public boolean isAccepting(State state) {
        return this.initial.equals(state) || nodes[0].isAccepting(state);
    }

    /**
     * @version 2.2.0
     * @see org.objectweb.fractal.bpc.checker.node.TreeNode#getTransitions(org.objectweb.fractal.bpc.checker.state.State)
     */
    /*
     * public TransitionPair[] getTransitions(State state) throws
     * InvalidParameterException, CheckingException { State initial =
     * nodes[0].getInitial();; TransitionPair[] origtrans =
     * nodes[0].getTransitions(state); int transcnt = origtrans.length;
     * ArrayList addedtrans = new ArrayList(); boolean acc = false;
     * 
     * for (int i = 0; i < transcnt; ++i) { if
     * (nodes[0].isAccepting(origtrans[i].state)) { acc = true;
     * addedtrans.add(new TransitionPair(origtrans[i].eventIndex, initial)); } }
     * 
     * if (acc) { TransitionPair[] newtrans = new TransitionPair[transcnt +
     * addedtrans.size()];
     * 
     * int i = 0; for (; i < transcnt; ++i) newtrans[i] = origtrans[i];
     * 
     * Iterator it = addedtrans.iterator();
     * 
     * while (it.hasNext()) newtrans[i++] = (TransitionPair)it.next();
     * 
     * 
     * return newtrans; } else return origtrans; }
     */

    /**
     * @see org.objectweb.fractal.bpc.checker.node.TreeNode#getTransitions(org.objectweb.fractal.bpc.checker.state.State)
     */
    public TransitionPairs getTransitions(State state) throws InvalidParameterException, CheckingException {
        State initial = nodes[0].getInitial();
        
        TransitionPair[] origtrans = nodes[0].getTransitions(state).transitions;
        int transcnt = origtrans.length;

        if (nodes[0].isAccepting(state)) {
            initial = nodes[0].getInitial();
            TransitionPair[] trans = nodes[0].getTransitions(initial).transitions;

            TransitionPair[] result = new TransitionPair[trans.length + transcnt];

            for (int i = 0; i < transcnt; ++i)
                result[i] = origtrans[i];

            for (int i = 0; i < trans.length; ++i)
                result[i + transcnt] = trans[i];

            return new TransitionPairs(result);
        }

        else {
            return new TransitionPairs(origtrans);
        }
    }


    /**
     * @see org.objectweb.fractal.bpc.checker.node.TreeNode#getWeight()
     */
    public long getWeight() {
        if (weight != -1)
            return weight;
        else {
            return weight = nodes[0].getWeight();
        }
    }

    /**
     * @return the symbolic name of the treenode denoting its type
     */
    public String[] getTypeName() {
        String[] result = { "Repetition", "*" };
        return result;
    }

    /**
     * @see org.objectweb.fractal.bpc.checker.node.TreeNode#forwardCut(TreeSet)
     */
    public TreeNode forwardCut(TreeSet livingevents) {

        nodes[0] = nodes[0].forwardCut(livingevents);
        if (nodes[0] != null) {
            if (nodes[0] instanceof RepetitionNode)
                return nodes[0];
            else
                return this;
        } else
            return null;

    }

    /**
     * @see org.objectweb.fractal.bpc.checker.node.TreeNode#getLeafCount()
     * @return number of children of subtree multiplicated by two for the case
     *         of nondeterminism.
     */
    public int getLeafCount() {
        return (nodes[0].getLeafCount()) * 2;
    }
    
    /**
     * @see org.objectweb.fractal.bpc.checker.node.TreeNode#getAnotatedProtocol(org.objectweb.fractal.bpc.checker.state.State)
     */
    public AnotatedProtocol getAnotatedProtocol(State state) {
        String result = new String();;
        ArrayList indices = new ArrayList();
        
        result = "(";
        
        AnotatedProtocol subresult = nodes[0].getAnotatedProtocol(state);
        
        for (int i = 0 ; i < subresult.indices.size(); ++i)
            indices.add(new Integer(((Integer)subresult.indices.get(i)).intValue() + result.length()));
        
        result += subresult.protocol + ")*";
        
        return new AnotatedProtocol(result, indices);
    }    

    //----------------------------------------------------------------------------------
    /**
     * The initial node - we need this for comparison during compliance test,
     * since the signatures are lazy evaluated.
     */
    private State initial;

}
